// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose: implementation of CImplMultipleTextSource.
//   $Id$
#include "stdafx.h"
#include "multipletextsource.h"
#include "model.h"
#include "xformsxformselement.h"
#include "dom3asls.h"
#include <Common/FileSystem/msw/FileSystemUtils.h>
#include "XFormsElement.h"
//TODO: implement parameterized constructor.
CImplMultipleTextSource::CImplMultipleTextSource(CXFormsElement* pEl)
:	CImplSingleNodeBinding(pEl)
	, m_bShouldRefresh(true)
{
	m_bShouldRefresh = true;
	m_bCanBindToValue = true;
}

CImplMultipleTextSource::CImplMultipleTextSource()
:m_bShouldRefresh(true)
{
	m_bShouldRefresh = true;
	m_bCanBindToValue = true;
}

HRESULT CImplMultipleTextSource::GetMultipleTextSource(BSTR * psText)
{
	HRESULT hr = S_OK;
	//Prevent infinite loop by link-error.
	bool bRefresh = m_bShouldRefresh;
	m_bShouldRefresh = false;

	/*
	 * If there is an href URI then retrieve that document
	 *	[DONE] This is not neccessarily XML 
	 *	[DONE] Check the order, for Message it is ref/href/inline
	 *		The order is consistently ref/href/inline 
	 */

	/*
	 * If there is a single node binding instruction then use that
	 */
	
	if(m_vertices.GetCount() > 0)
	{
		//This branch handles both @bind and @ref.
		__super::GetBoundData(psText);
	}
	else if (m_sRef.Length() > 0 && m_pModel)
	{
		CComPtr<IXMLDOMNode> pContext;
		GetEvaluationContext(&pContext);
		m_pXForms->putXPathIdentityResolver(GetIdResolver());
		hr = m_pModel->getInstanceString(m_sRef,pContext, psText);
		m_pXForms->putXPathIdentityResolver(0);
	}	
	else if (m_sHref)
	{
		CDocumentLS doc;
		CComBSTR bs;
		bs.Attach(Relative2AbsolutePath(this->m_pXForms->m_sCurrentURL,m_sHref));
		
		if(::wcsstr(bs,L"file://") == bs.m_str)
		{
			char * sFileName = BSTRToStr(bs);
			char * sFileContent = 0;
			hr = xport::ReadFromFileSystem(&(sFileName[7]),reinterpret_cast<void**>(&sFileContent));
			if(SUCCEEDED(hr))
			{
				CComBSTR bsContent(sFileContent);
				*psText = bsContent.Detach();
			}
			delete [] sFileName;
			delete [] sFileContent;
		}
		else
			hr = ::fetchHTTPDocument(bs, psText);
		if(FAILED(hr))
		{
			//Fire the link error.  If This control is attached to a model, fire it on that.
			//	otherwise fire it on the default model.
			if(m_pModel)
			{
				m_pModel->onLinkError(m_sHref);
			}
			else
			{
				CImplModel* pModel = 0;
				m_pXForms->getModel(NULL,pModel);
				pModel->onLinkError(m_sHref);
			}
		}

	}


	/*
	 * Otherwise, our data is inline
	 */

	else
		*psText = ::SysAllocString(m_sContent);
	
	m_bShouldRefresh = bRefresh;
	return hr;
}

// outputs and labels  are allowed to bind to non-nodes if they use @value
void CImplMultipleTextSource::onBindToNothing(void)
{
	if(!m_bCanBindToValue)
		__super::onBindToNothing();
}


HRESULT CImplMultipleTextSource::init(CImpl * pParent)
{
	if((!!m_sValueAttr) && (!m_sRef))
	{
		//TEMP, FUDGE, copy value into ref
		m_sRef = m_sValueAttr;
		m_sValueAttr.Empty();
		//m_bMustBindToNode = false;
		m_bCanBindToValue = true;
	}

	if (!m_sRef && !m_sBind)
	{
		//without a ref attribute, it is bound to no model,
		//	and probably contains inline content or an external
		//	href, setting this property ensures that it becomes
		//	an "orphan" in the eyes of the form and  only puts
		//	data into the UI control once.
		m_bisBound = false;
		if(m_pXFormsElement)
			m_pXFormsElement->put_value(m_sContent);
	}
	FlushHoldingList();
	return __super::init(pParent);
}


bool CImplMultipleTextSource::AddControl(CImplNodeBinding *pControl)
{
	bool bRet = false;
	if(m_bInitializeDone)
	{
		if(m_bisBound)
		{
			bRet = __super::AddControl(pControl);
		}
		else
		{
			if(m_pParentImpl && dynamic_cast<CImplNodeBinding*>(m_pParentImpl))
			{
				bRet = ((CImplNodeBinding*)m_pParentImpl)->AddControl(pControl);
			}
		}
	}
	else
	{
		m_ReliantControlHoldingList.AddHead(pControl);
		bRet = true;
	}

	return bRet;
}

void CImplMultipleTextSource::FlushHoldingList()
{
	//if unbound, promote to ancestor
	if(m_bisBound)
	{
		while(!m_ReliantControlHoldingList.IsEmpty())
		{
			CImplNodeBinding * pControl = m_ReliantControlHoldingList.RemoveHead();
			__super::AddControl(pControl);
		}
	}
	else
	{
		if(m_pParentImpl && dynamic_cast<CImplNodeBinding*>(m_pParentImpl))
		{
			while(!m_ReliantControlHoldingList.IsEmpty())
			{
				CImplNodeBinding * pControl = m_ReliantControlHoldingList.RemoveHead();
				((CImplNodeBinding*)m_pParentImpl)->AddControl(pControl);
			}
		}
		else
		{
			while(!m_ReliantControlHoldingList.IsEmpty())
			{
				CImplNodeBinding * pControl = m_ReliantControlHoldingList.RemoveHead();
				if(pControl->m_pModel)
				{
					pControl->m_pModel->AddFormControl(pControl);
				}
				else
				{
					m_pXForms->AddControl(pControl);
				}
			}
		}
	}
}